package rs.fon.is.music.parser;

import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;

import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import rs.fon.is.music.domain.Country;
import rs.fon.is.music.domain.Event;
import rs.fon.is.music.domain.GeoCoordinates;
import rs.fon.is.music.domain.Place;
import rs.fon.is.music.domain.PostalAddress;
import rs.fon.is.music.parser.exceptions.EventNotFoundException;
import rs.fon.is.music.persistence.DataModelManager;
import rs.fon.is.music.util.URIGenerator;

public class EventParser implements DomainClassParser<Event> {
	
	protected Logger logger = Logger.getLogger(this.getClass().getName());

	public LinkedList<Event> parseEvents(String url){

		Document doc;
		
		try {
			doc = Jsoup.connect(url + "/+events").get();
			
			LinkedList<Event> events = new LinkedList<>();

			String noHttp = url.substring(7, url.length());
			String domain = noHttp.substring(0, noHttp.indexOf('/'));

			Elements eventElements = doc.getElementsByClass("vevent");

			for (Element eventElement : eventElements) {

				Elements urlElements = eventElement.getElementsByClass("url");

				if (urlElements.size() > 0) {

					String eventURL = urlElements.first().attr("href");
					if (!eventURL.startsWith("http://" + domain))
						eventURL = "http://" + domain + eventURL;

					Event event = parse(eventURL);

					// name
					if (eventElement.getElementsByClass("summary").size() > 0)
						event.setName(eventElement.getElementsByClass("summary").first().text());

					// geo
					if (eventElement.getElementsByClass("geo").size() > 0) 
						event.getLocation().setGeo(parseGeo(eventElement));
					
					DataModelManager.getInstance().save(event);
			
					events.add(event);
					
				}
			}

			return events;
			
		} catch (Exception ex) {
			logger.error("Error while parsing events on URL '" + url + "'. " + ex);
			System.err.println("Error while parsing events on URL '" + url + "'. " + ex);
			return parseEvents(url);
		}

	}

	@Override
	public Event parse(String url){

		Document doc;

		try {
			
			doc = Jsoup.connect(url).get();
			
			Elements eventElements = doc.getElementsByClass("vevent");

			if (eventElements.size() > 0) {

				Event event = new Event();

				Element eventElement = eventElements.first();

				// URI
				event.setUri(URIGenerator.generate(event));

				// URL
				event.setUrl(new URI(url));

				// startDate
				if (eventElement.getElementsByClass("dtstart").size() > 0) {
					String dateString = eventElement.getElementsByClass("dtstart").first().attr("title");
					String pattern = "yyyy-MM-dd'T'HH:mm:ss";
					SimpleDateFormat sdf = new SimpleDateFormat(pattern);
					Date date = sdf.parse(dateString);
					event.setStartDate(date);
				}
				
				// endDate
				if (eventElement.getElementsByClass("dtend").size() > 0) {
					String dateString = eventElement.getElementsByClass("dtend").first().attr("title");
					String pattern = "yyyyMMdd'T0000Z'";
					SimpleDateFormat sdf = new SimpleDateFormat(pattern);
					Date date = sdf.parse(dateString);
					event.setEndDate(date);
				}

				// location
				if (eventElement.getElementsByClass("location").size() > 0) {
					Element locationElement = eventElement.getElementsByClass("location").first();
					event.setLocation(parsePlace(locationElement));
				}

				return event;
				
			} else
				
				throw new EventNotFoundException("schema:Event instance is not found on this URL.");
		
		} catch (EventNotFoundException ex){
			logger.error("Error while parsing event on URL '" + url + "'. " + ex);
			System.err.println("Error while parsing event on URL '" + url + "'. " + ex);
			return null;
			
		} catch (Exception ex){
			logger.error("Error while parsing event on URL '" + url + "'. " + ex);
			System.err.println("Error while parsing event on URL '" + url + "'. " + ex);
			return parse(url);
		}

	}

	public Place parsePlace(Element e){

		try {
			Place place = new Place();

			// URI
			place.setUri(URIGenerator.generate(place));

			// URL
			if (e.getElementsByClass("url").size() > 0)
				place.setUri(new URI(e.getElementsByClass("url").first().attr("href")));

			// name
			if (e.getElementsByClass("fn").size() > 0)
				place.setName(e.getElementsByClass("fn").first().text());

			// telephone
			if (e.getElementsByClass("tel").size() > 0)
				place.setTelephone(e.getElementsByClass("tel").first().text());

			// address
			if (e.getElementsByClass("adr").size() > 0) {
				Element adrElement = e.getElementsByClass("adr").first();
				place.setAddress(parsePostalAddress(adrElement));
			}

			return place;
			
		} catch (Exception ex) {
			logger.error("Error while parsing event - place. " + ex);
			System.err.println("Error while parsing event - place. " + ex);
			return null;
		}
	}

	public PostalAddress parsePostalAddress(Element e){

		try {
			PostalAddress address = new PostalAddress();

			// URI
			address.setUri(URIGenerator.generate(address));

			// streetAddress
			if (e.getElementsByClass("street-address").size() > 0)
				address.setStreetAddress(e.getElementsByClass("street-address").first().text());

			// addressLocality
			if (e.getElementsByClass("locality").size() > 0)
				address.setAddressLocality(e.getElementsByClass("locality").first().text());

			// addressRegion
			if (e.getElementsByClass("region").size() > 0)
				address.setAddressRegion(e.getElementsByClass("region").first().text());

			// postalCode
			if (e.getElementsByClass("postal-code").size() > 0)
				address.setPostalCode(e.getElementsByClass("postal-code").first().text());

			// country
			if (e.getElementsByClass("country-name").size() > 0)
				address.setAddressCountry(parseCountry(e));

			return address;
			
		} catch (Exception ex) {
			logger.error("Error while parsing event - address. " + ex);
			System.err.println("Error while parsing event - address. " + ex);
			return null;
		}
	}

	public Country parseCountry(Element e) {

		try {
			Country country = new Country();

			// URI
			country.setUri(URIGenerator.generate(country));

			// name
			if (e.getElementsByClass("country-name").size() > 0)
				country.setName(e.getElementsByClass("country-name").first().text());

			return country;
			
		} catch (Exception ex) {
			logger.error("Error while parsing event - country. " + ex);
			System.err.println("Error while parsing event - country. " + ex);
			return null;
		}

	}

	public GeoCoordinates parseGeo(Element e) {

		try {
			
			GeoCoordinates geo = new GeoCoordinates();
			// URI
			geo.setUri(URIGenerator.generate(geo));

			// latitude
			if (e.getElementsByClass("geo").first().getElementsByClass("latitude").size() > 0)
				geo.setLatitude(Double.parseDouble(e.getElementsByClass("geo").first().getElementsByClass("latitude").text()));

			// longitude
			if (e.getElementsByClass("geo").first().getElementsByClass("longitude").size() > 0)
				geo.setLongitude(Double.parseDouble(e.getElementsByClass("geo").first().getElementsByClass("longitude").text()));

			return geo;
		
		} catch (Exception ex) {
			logger.error("Error while parsing event - coordinates. " + ex);
			System.err.println("Error while parsing event - coordinates. " + ex);
			return null;
		}
	}

}
